/**********************************************************************************************************************
 *
 * Project:    mGameEngine
 * File:       mesh.h
 * Author:     karooolek
 * Created on: 2009-03-14
 *
 **********************************************************************************************************************/

#ifndef MESH_H_
#define MESH_H_

#include "drawable.h"
#include "vertex.h"
#include "group.h"
#include "bone.h"
#include "glee.h"

namespace mGameEngine
{
namespace Graphics
{

/**
 * Three dimensional, animated mesh.
 * TODO some more of opis...?
 */
class Mesh : public Drawable
{
protected:
    /**
     * Vertices.
     */
    Vector<Vertex> _vertices;

    /**
     * Geometry groups.
     */
    Vector<Group> _groups;

    /**
     * Bones.
     */
    Vector<Bone> _bones;

    /**
     * Lower level of detail mesh.
     */
    Mesh *_lowerLodMesh;

    /**
     * Update bounding sphere.
     */
    virtual void _updateBoundingSphere();

public:
    /**
     * Create new empty mesh.
     */
    Mesh();

    /**
     * Create new mesh with specified vertices and groups.
     * @param vertices vertices.
     * @param groups geometry groups.
     * @param bones bones.
     */
    Mesh(    const Vector<Vertex> &vertices,
            const Vector<Group> &groups,
            const Vector<Bone> &bones);

    /**
     * Destroy mesh.
     */
    virtual ~Mesh();

    /**
     * Get mesh vertices.
     * @return mesh vertices.
     */
    const Vector<Vertex> &getVertices() const
    {
        return _vertices;
    }

    /**
     * Set mesh vertices.
     * @param vertices vertices.
     */
    void setVertices(const Vector<Vertex> &vertices);

    /**
     * Get mesh geometry groups.
     * @return mesh geometry groups.
     */
    const Vector<Group> &getGroups() const
    {
        return _groups;
    }

    /**
     * Set mesh geometry groups.
     * @param groups geometry groups.
     */
    void setGroups(const Vector<Group> &groups);

    /**
     * Check if mesh has group with specified name.
     * @param groupName group name.
     * @return true if mesh has group with specified name, false otherwise.
     */
    bool hasGroup(const String &groupName) const;

    /**
     * Get group with specified name.
     * @param groupName group name.
     * @return group with specified name.
     */
    const Group &getGroup(const String &groupName) const;

    /**
     * Get mesh bones.
     * @return mesh bones.
     */
    const Vector<Bone> &getBones() const
    {
        return _bones;
    }

    /**
     * Set mesh bones.
     * @param bones bones.
     */
    void setBones(const Vector<Bone> &bones);

    /**
     * Check if mesh has bone with specified name.
     * @param boneName group name.
     * @return true if mesh has bone with specified name, false otherwise.
     */
    bool hasBone(const String &boneName) const;

    /**
     * Get bone with specified name.
     * @param boneName bone name.
     * @return bone with specified name.
     */
    const Bone &getBone(const String &boneName) const;

    /**
     * Calculate normals.
     */
    void calculateNormals();

    /**
     * Calculate tangents.
     */
    void calculateTangents();

    /**
     * Get lower level of detail mesh.
     * @return lower level of detail mesh.
     */
    Mesh *getLowerLODMesh() const
    {
        return _lowerLodMesh;
    }

    /**
     * Set lower level of detail mesh.
     * @param mesh mesh.
     */
    void setLowerLODMesh(Mesh *mesh)
    {
        _lowerLodMesh = mesh;
    }

    /**
     * Generate lower level of deatail meshes.
     * Actual lower level of detail meshes will be overriden.
     * @param levels number of lower LOD meshes to generate.
     * @param vertReduction percentage of deleted vertices.
     * Value must be between 0.0 and 1.0.
     */
    virtual void generateLowerLODMeshes(uint8 levels,
                                        float vertReduction = 0.5f);

    /**
     * Draw mesh.
     */
    virtual void draw() const;
};

}
}

#endif // MESH_H_
